package com.sprucetec.live.util;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.sprucetec.hawkeye.sdk.trace.httpclient.TraceHttpClientBuilder;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Http client
 *
 * @author panzhiqi
 * modified by lizhenbin t-2018.12.03
 */
@Component
@Slf4j
public class HttpClientUtil {

    //钉钉接口返回参数常量-begin
    public static final String DINGTALK_API_OK = "0";
    public static final String DINGTALK_API_ERRORCODE = "errcode";
    public static final String DINGTALK_API_USERID = "userid";
    public static final String DINGTALK_API_JOBNUMBER = "jobnumber";
    //钉钉接口返回参数常量-end

    private static final int MAX_SOCKET_TIMEOUT = 1000;
    private static final int MAX_CONNECT_TIMEOUT = 1000;

    private CloseableHttpClient httpClient;

    public HttpClientUtil() {
        httpClient = HttpClients.createDefault();
    }

    public String get(String url) {
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(MAX_SOCKET_TIMEOUT)
                .setConnectTimeout(MAX_CONNECT_TIMEOUT).build();

        HttpGet httpget = new HttpGet(url);
        httpget.setConfig(requestConfig);
        CloseableHttpResponse response = null;
        String responseString = null;
        try {
            response = httpClient.execute(httpget);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                return EntityUtils.toString(entity);
            }
        } catch (IOException e) {
            log.error("异常:[{}]", e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                log.warn("response is not closed");
            }
        }
        return responseString;
    }

    /**
     * get请求
     * @deprecated 不建议使用，该接口吃掉了异常，没有给上层使用者返回真正的异常 update by lixiaodong on 2020-01-06
     * @param url
     * @param timeOut
     * @return 成功返回json对象
     */
    public JSONObject get(String url,int timeOut) {
        JSONObject reMsg = new JSONObject(true);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeOut).build();
        HttpClient client = TraceHttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
        if (timeOut == -1) {
            client = TraceHttpClientBuilder.create().build();
        }
        HttpGet httpget = new HttpGet(url);
        httpget.setConfig(requestConfig);
        try {
            HttpResponse response = client.execute(httpget);
            if (response.getStatusLine().getStatusCode() == 200) {
                String str = EntityUtils.toString(response.getEntity());
                LinkedHashMap<String, Object> json = JSON.parseObject(str,LinkedHashMap.class, Feature.OrderedField);
                reMsg.putAll(json);
            } else {
                reMsg.put("replyDesc",response.getStatusLine().getStatusCode());
            }
            return reMsg;
        } catch (Exception e) {
            log.error("异常:[{}]", e);
            reMsg.put("replyDesc","timeout");
        }
        return reMsg;
    }

    /**
     * http get请求
     * @param txNo 业务日志
     * @param url http请求地址
     * @param socketTimeOut 单位ms，户端和服务进行数据交互的时间，是指两者之间如果两个数据包之间的时间大于该时间则认为超时
     * @param connectionRequestTimeout 单位ms，从连接池获取到连接的超时时间，如果是非连接池的话，该参数暂时没有发现有什么用处
     * @param connectTimeout 单位ms，建立连接的超时时间
     * @return http请求响应结果
     * @throws Exception 异常
     */
    public JSONObject getV1(String txNo, String url, int socketTimeOut, int connectionRequestTimeout, int connectTimeout) {
        JSONObject reMsg = new JSONObject(true);
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).
                setConnectionRequestTimeout(connectionRequestTimeout).
                setSocketTimeout(socketTimeOut).build();
        HttpClient client = TraceHttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
        HttpGet httpget = new HttpGet(url);
        httpget.setConfig(requestConfig);
        try {
            HttpResponse response = client.execute(httpget);
            if (response.getStatusLine().getStatusCode() == 200) {
                String str = EntityUtils.toString(response.getEntity());
                LinkedHashMap<String, Object> json = JSON.parseObject(str,LinkedHashMap.class, Feature.OrderedField);
                reMsg.putAll(json);
            } else {
                log.warn("txNo:[{}],HTTP请求状态异常:[{}]",txNo, response.getStatusLine());
                reMsg.put("replyDesc",response.getStatusLine().toString());
            }
        } catch (Exception e) {
            log.error("txNo:[{}],异常:[{}]",txNo, e);
            reMsg.put("replyDesc",StringUtils.isEmpty(e.getMessage())?"未知错误":e.getMessage());
        }
        return reMsg;
    }

    /**
     * 从url中解析参数parameters的键值对
     *
     * @param url
     * @param parameters
     * @return
     */
    public Map<String, String> getNameValuePair(String url, String[] parameters) {
        Map<String, String> res = new HashMap<String, String>();
        String u = null;
        try {
            u = URLDecoder.decode(url, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        for (String s : parameters) {
            Pattern p = Pattern.compile(s + "=([^&]*)(&|$)");
            Matcher m = p.matcher(u);
            if (m.find()) {
                res.put(s, m.group(1));
            }
        }
        return res;
    }

    public JSONObject post(String url, String jsons) throws Exception{
        JSONObject reMsg = null;
        StringEntity params = new StringEntity(jsons.toString(),"UTF-8");
        HttpClient client = TraceHttpClientBuilder.create().build();
        HttpPost post = new HttpPost(url);
        post.setHeader(HTTP.CONTENT_TYPE, "application/json;charset=UTF-8");
        post.setHeader("text/html", "charset=UTF-8");
        post.setEntity(params);
        HttpResponse response = client.execute(post);
        if (response.getStatusLine().getStatusCode() == 200) {
            String str = EntityUtils.toString(response.getEntity());
            reMsg = JSONObject.parseObject(str);
        }
        return reMsg;
    }

    /**
     * post 设置超时时间
     * @deprecated 不建议使用，该接口吃掉了异常，没有给上层使用者返回真正的异常 update by lixiaodong on 2020-01-06
     * @param url
     * @param jsons
     * @param timeOut
     * @return
     * @throws Exception
     */
    public JSONObject post(String url, String jsons, int timeOut) throws Exception{
        JSONObject reMsg = new JSONObject(true);
        StringEntity params = new StringEntity(jsons.toString(),"UTF-8");
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeOut).build();
        HttpClient client = TraceHttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
        if (timeOut == -1) {
            client = TraceHttpClientBuilder.create().build();
        }
        HttpPost post = new HttpPost(url);
        post.setHeader(HTTP.CONTENT_TYPE, "application/json;charset=UTF-8");
        post.setEntity(params);
        try {
            HttpResponse response = client.execute(post);
            if (response.getStatusLine().getStatusCode() == 200) {
                String str = EntityUtils.toString(response.getEntity());
                LinkedHashMap<String, Object> json = JSON.parseObject(str,LinkedHashMap.class, Feature.OrderedField);
                reMsg.putAll(json);
            } else {
                reMsg.put("replyDesc","timeout");
            }
            return reMsg;
        } catch(Exception e) {
            log.error("异常:[{}]", e);
            reMsg.put("replyDesc","timeout");
        }
        return reMsg;
    }

    /**
     * http post请求
     * @param txNo 业务日志
     * @param url http请求地址
     * @param jsons http请求参数（json格式）
     * @param socketTimeOut 单位ms，户端和服务进行数据交互的时间，是指两者之间如果两个数据包之间的时间大于该时间则认为超时
     * @param connectionRequestTimeout 单位ms，从连接池获取到连接的超时时间，如果是非连接池的话，该参数暂时没有发现有什么用处
     * @param connectTimeout 单位ms，建立连接的超时时间
     * @return http请求响应结果
     * @throws Exception 异常
     */
    public JSONObject postV1(String txNo, String url, String jsons, int socketTimeOut, int connectionRequestTimeout, int connectTimeout) throws Exception{
        JSONObject reMsg = new JSONObject(true);
        StringEntity params = new StringEntity(jsons.toString(),"UTF-8");
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).
                setConnectionRequestTimeout(connectionRequestTimeout).
                setSocketTimeout(socketTimeOut).build();
        HttpClient client = TraceHttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
        HttpPost post = new HttpPost(url);
        post.setHeader(HTTP.CONTENT_TYPE, "application/json;charset=UTF-8");
        post.setEntity(params);
        try {
            HttpResponse response = client.execute(post);
            if (response.getStatusLine().getStatusCode() == 200) {
                String str = EntityUtils.toString(response.getEntity());
                LinkedHashMap<String, Object> json = JSON.parseObject(str,LinkedHashMap.class, Feature.OrderedField);
                reMsg.putAll(json);
            } else {
                log.warn("txNo:[{}],HTTP请求状态异常:[{}]",txNo, response.getStatusLine());
                reMsg.put("replyDesc",response.getStatusLine().toString());
            }
        } catch(Exception e) {
            log.error("txNo:[{}],异常:[{}]",txNo, e);
            reMsg.put("replyDesc",StringUtils.isEmpty(e.getMessage())?"未知错误":e.getMessage());
        }
        return reMsg;
    }

    /**
     * 判断是否是移动设备
     * @param userAgent User-Agent头
     * @return
     */
    public static boolean isMobileDevice(String userAgent){

        String[] deviceArray = new String[]{"android","ipad","iphone os","midp","rv:1.2.3.4","ucweb","windows ce","windows mobile"};
        if(userAgent == null)
            return false;
        userAgent = userAgent.toLowerCase();
        for(int i=0;i<deviceArray.length;i++){
            if(userAgent.indexOf(deviceArray[i])>0){
                return true;
            }
        }
        return false;
    }

    /**
     * 获取用户客户端IP
     * @param request
     * @return
     */
    public static String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("x-forwarded-for");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
